package edu.scau.divineplace.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import edu.scau.divineplace.entity.dos.*;
import edu.scau.divineplace.entity.enums.CommentTargetTypeEnum;
import edu.scau.divineplace.entity.enums.ContentTypeEnum;
import edu.scau.divineplace.entity.enums.RoleTruthEnum;
import edu.scau.divineplace.entity.enums.RoleTypeEnum;
import edu.scau.divineplace.entity.query.content.*;
import edu.scau.divineplace.entity.vo.content.CvVO;
import edu.scau.divineplace.entity.vo.content.RoleVO;
import edu.scau.divineplace.entity.vo.content.SuggestionVO;
import edu.scau.divineplace.util.BeanConvertUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Author: x1aolone
 * @Date: 2020/12/9 13:33
 */
@Service
public class ContentService {

    @Autowired
    private ImportMapperService importMapperService;

    /**
     * 获取内容的角色/制作人
     * @param contentId
     * @param roleType
     * @return
     */
    public List<RoleVO> listRoles(Long contentId, RoleTypeEnum roleType) {
        List<RoleVO> VOList = Lists.newArrayList();
        LambdaQueryWrapper<ContentRoleRelationDO> relationQuery = Wrappers.<ContentRoleRelationDO>lambdaQuery()
                .eq(ContentRoleRelationDO::getContentId, contentId)
                .eq(ContentRoleRelationDO::getRoleType, roleType);
        List<ContentRoleRelationDO> relationDOList = importMapperService.contentRoleRelationMapper.selectList(relationQuery);
        for (ContentRoleRelationDO relationDO : relationDOList) {
            Long roleId = relationDO.getRoleId();
            // 获取人物信息
            ContentBasicInformationDO roleBasicInfoDO = importMapperService.contentBasicInformationMapper.selectById(roleId);
            List<RoleVO> cvs = Lists.newArrayList();
            if (roleType == RoleTypeEnum.PART) {
                // 如果是角色，找一下CV列表
                LambdaQueryWrapper<RoleCvRelationDO> cvRelationQuery = Wrappers.<RoleCvRelationDO>lambdaQuery()
                        .eq(RoleCvRelationDO::getRoleId, roleId)
                        .eq(RoleCvRelationDO::getContentId, contentId);
                List<RoleCvRelationDO> cvRelationDOS = importMapperService.roleCvRelationMapper.selectList(cvRelationQuery);
                // 获取每一个cv的信息
                cvRelationDOS.forEach(x -> {
                    ContentBasicInformationDO basicDO = importMapperService.contentBasicInformationMapper.selectById(x.getCvId());
                    RoleVO cvVO = BeanConvertUtils.DO2BO(basicDO, RoleVO.class);
                    cvVO.setRoleId(basicDO.getId());
                    cvVO.setRelationId(x.getId());
                    cvs.add(cvVO);
                });
            }
            RoleVO VO = RoleVO.builder()
                    .originalName(roleBasicInfoDO.getOriginalName())
                    .chineseName(roleBasicInfoDO.getChineseName())
                    .introductionImg(roleBasicInfoDO.getIntroductionImg())
                    .roleId(relationDO.getRoleId())
                    .relationId(relationDO.getId())
                    .roleTypeDetail(relationDO.getRoleTypeDetail())
                    .cvs(cvs)
                    .build();
            VOList.add(VO);
        }
        return VOList;
    }


    /**
     * 通过内容名和类型，获取输入建议
     * @param query
     */
    public List<SuggestionVO> getSuggestion(SuggestionQuery query) {
        String originalName = (originalName = query.getOriginalName()) == null ? "" : originalName;
        ContentTypeEnum type = query.getType();
        RoleTruthEnum roleTruth = query.getRoleTruth();
        LambdaQueryWrapper<ContentBasicInformationDO> basicInfoQuery = Wrappers.<ContentBasicInformationDO>lambdaQuery()
                .like(ContentBasicInformationDO::getOriginalName, originalName)
                .eq(ContentBasicInformationDO::getType, type);
        List<ContentBasicInformationDO> DOS = importMapperService.contentBasicInformationMapper.selectList(basicInfoQuery);
        // 如果是人物，需要筛选一下人物的真实性
        if (type == ContentTypeEnum.ROLE && roleTruth != null) {
            DOS = filteByIsReal(DOS, roleTruth);
        }
        List<SuggestionVO> VOS = BeanConvertUtils.DOs2BOs(DOS, SuggestionVO.class);
        VOS.forEach(VO -> VO.setValue(VO.getOriginalName()));
        return VOS;
    }

    public List<ContentBasicInformationDO> filteByIsReal(List<ContentBasicInformationDO> list, RoleTruthEnum roleTruth) {
        list =  list.stream()
                .filter(basicInfo -> {
                    LambdaQueryWrapper<RoleTruthDO> roleTruthQuery = Wrappers.<RoleTruthDO>lambdaQuery()
                            .eq(RoleTruthDO::getRoleId, basicInfo.getId())
                            .eq(RoleTruthDO::getRoleTruth, roleTruth);
                    int count = importMapperService.roleTruthMapper.selectCount(roleTruthQuery);
                    return count > 0;
                })
                .collect(Collectors.toList());
        return list;
    }

    /**
     * 上传内容信息
     * @param contentManageQuery
     */
    @Transactional(rollbackFor = Exception.class)
    public void upload(ContentManageQuery contentManageQuery) {
        // basic信息
        ContentBasicInformationDO basicDO = BeanConvertUtils.BO2DO(contentManageQuery.getBasicInfo(), ContentBasicInformationDO.class);
        importMapperService.contentBasicInformationMapper.insert(basicDO);
        Long contentId = basicDO.getId();
        // 额外信息
        List<ContentExtraInfoQuery> extraInfos = contentManageQuery.getExtraInfos();
        List<ContentExtraInformationDO> extraDOs = BeanConvertUtils.BOs2DOs(extraInfos, ContentExtraInformationDO.class);
        for (ContentExtraInformationDO extraDO : extraDOs) {
            extraDO.setContentId(contentId);
            importMapperService.contentExtraInformationMapper.insert(extraDO);
        }
        // 根据内容类型进行不同的处理
        ContentTypeEnum contentType = basicDO.getType();
        if (contentType.isACG()) {
            // 处理角色
            for (RoleManageQuery role : contentManageQuery.getParts()) {
                ContentRoleRelationDO roleRelationDO = BeanConvertUtils.BO2DO(role, ContentRoleRelationDO.class);
                roleRelationDO.setContentId(contentId);
                roleRelationDO.setRoleType(RoleTypeEnum.PART);
                importMapperService.contentRoleRelationMapper.insert(roleRelationDO);
                // 游戏或者动漫, 处理CV
                if (contentType != ContentTypeEnum.COMICS) {
                    List<Long> cvsId = role.getCvs().stream().map(RoleManageQuery::getRoleId).collect(Collectors.toList());
                    RoleCvRelationDO roleCvRelationDO = BeanConvertUtils.BO2DO(role, RoleCvRelationDO.class);
                    roleCvRelationDO.setContentId(contentId);
                    roleCvRelationDO.setRoleId(role.getRoleId());
                    for (Long cvId : cvsId) {
                        roleCvRelationDO.setCvId(cvId);
                        importMapperService.roleCvRelationMapper.insert(roleCvRelationDO);
                    }
                }
            }
        }
        else if (contentType == ContentTypeEnum.MUSIC) {
            // 处理Disc
            List<ContentDiscQuery> discs = contentManageQuery.getDiscs();
            long discNum = getMaxDiscNum(contentId);
            for (ContentDiscQuery disc : discs) {
                discNum++;
                for (ContentSongQuery song : disc.getMusicDiscList()) {
                    MusicDiscListDO discDO = BeanConvertUtils.BO2DO(song, MusicDiscListDO.class);
                    discDO.setContentId(contentId);
                    discDO.setDisc(discNum);
                    importMapperService.musicDiscListMapper.insert(discDO);
                }
            }
        }
        else if (contentType == ContentTypeEnum.ROLE) {
            // 处理人物真实性
            RoleTruthEnum roleTruth = contentManageQuery.getRoleTruth();
            RoleTruthDO DO = new RoleTruthDO();
            DO.setRoleId(contentId);
            DO.setRoleTruth(roleTruth);
            importMapperService.roleTruthMapper.insert(DO);
        }
        // 处理制作人
        if (contentType.isACG() || contentType == ContentTypeEnum.MUSIC) {
            for (RoleManageQuery producer : contentManageQuery.getProducers()) {
                ContentRoleRelationDO roleRelationDO = BeanConvertUtils.BO2DO(producer, ContentRoleRelationDO.class);
                roleRelationDO.setContentId(contentId);
                roleRelationDO.setRoleType(RoleTypeEnum.PRODUCER);
                importMapperService.contentRoleRelationMapper.insert(roleRelationDO);
            }
        }
    }

    /**
     * 通过内容 Id 去获取这个音乐的 Disc 的最大序号
     * 如果没有 Disc, 返回值为 0
     * @param contentId
     * @return
     */
    public Long getMaxDiscNum (Long contentId) {
        LambdaQueryWrapper<MusicDiscListDO> queryWrapper = Wrappers.<MusicDiscListDO>lambdaQuery()
                .eq(MusicDiscListDO::getContentId, contentId)
                .orderByDesc(MusicDiscListDO::getDisc)
                .last("limit 1");
        MusicDiscListDO DO = importMapperService.musicDiscListMapper.selectOne(queryWrapper);
        System.err.println(DO);
        return DO == null ? 0 : DO.getDisc();
    }

    /**
     * 更新内容信息
     * @param contentManageQuery
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public void update(ContentManageQuery contentManageQuery) {
        // 更新basic信息
        ContentBasicInfoQuery basicInfo = contentManageQuery.getBasicInfo();
        updateBasicInfo(basicInfo);
        Long contentId = basicInfo.getId();
        ContentTypeEnum contentType = basicInfo.getType();
        // 额外信息
        updateExtraInfo(contentId, contentManageQuery.getExtraInfos());
        // 根据内容类型进行不同的处理
        if (contentType.isACG()) {
            updateRoleInfo(contentId, contentType, contentManageQuery.getParts(), RoleTypeEnum.PART);
        }
        else if (contentType == ContentTypeEnum.MUSIC) {
            updateDiscInfo(contentId, contentManageQuery.getDiscs());
        }
        else if (contentType == ContentTypeEnum.ROLE) {
            updateRoleTruth(contentId, contentManageQuery.getRoleTruth());
        }
        // 处理制作人
        if (contentType.isACG() || contentType == ContentTypeEnum.MUSIC) {
            updateRoleInfo(contentId, null, contentManageQuery.getProducers(), RoleTypeEnum.PRODUCER);
        }
    }

    /**
     * 更新基本信息
     * @param basicInfo
     * @return
     */
    public void updateBasicInfo (ContentBasicInfoQuery basicInfo) {
        ContentBasicInformationDO basicDO = BeanConvertUtils.BO2DO(basicInfo, ContentBasicInformationDO.class);
        importMapperService.contentBasicInformationMapper.updateById(basicDO);
    }

    public void updateExtraInfo (Long contentId, List<ContentExtraInfoQuery> extraInfos) {
        List<ContentExtraInformationDO> extraDOS = BeanConvertUtils.BOs2DOs(extraInfos, ContentExtraInformationDO.class);
        // 如果有id就用id更新 没id就插入 不在这些id里面的就代表被删了
        List<Long> extraInfoIds = extraDOS.stream().map(ContentExtraInformationDO::getId).filter(Objects::nonNull).collect(Collectors.toList());
        // 当里面存在null值时, notIn的查询筛选一定是0条, 删除会失败
        if (extraInfoIds.size() > 0) {
            LambdaQueryWrapper<ContentExtraInformationDO> extraWrapper = Wrappers.<ContentExtraInformationDO>lambdaQuery()
                    .eq(ContentExtraInformationDO::getContentId, contentId)
                    .notIn(ContentExtraInformationDO::getId, extraInfoIds);
            importMapperService.contentExtraInformationMapper.delete(extraWrapper);
        }
        for (ContentExtraInformationDO extraDO : extraDOS) {
            if (extraDO.getId() == null) {
                extraDO.setContentId(contentId);
                importMapperService.contentExtraInformationMapper.insert(extraDO);
            } else {
                importMapperService.contentExtraInformationMapper.updateById(extraDO);
            }
        }
    }

    public void updateRoleInfo (Long contentId, ContentTypeEnum contentType,
                                List<RoleManageQuery> roles, RoleTypeEnum roleType) {
        // 处理角色，只有两种，一种是删了，一种是没删
        // 1. 被删了, id不在列表里面, delete
        // 2. 没有变动, id在列表里面
        // 3. 新增, id在列表里面, insert
        // 需要把不在列表里的删除，还要把不再数据库里的新增
        List<Long> roleRelationIds = roles.stream().map(RoleManageQuery::getRelationId).filter(Objects::nonNull).collect(Collectors.toList());
        // 删除角色
        if (roleRelationIds.size() > 0) {
            LambdaQueryWrapper<ContentRoleRelationDO> roleWrapper = Wrappers.<ContentRoleRelationDO>lambdaQuery()
                    .eq(ContentRoleRelationDO::getContentId, contentId)
                    .eq(ContentRoleRelationDO::getRoleType, roleType)
                    .notIn(ContentRoleRelationDO::getId, roleRelationIds);
            importMapperService.contentRoleRelationMapper.delete(roleWrapper);
        }
        // 新增角色
        for (RoleManageQuery role : roles) {
            ContentRoleRelationDO roleRelationDO = BeanConvertUtils.BO2DO(role, ContentRoleRelationDO.class);
            if (role.getRelationId() == null) {
                roleRelationDO.setContentId(contentId);
                roleRelationDO.setRoleType(roleType);
                importMapperService.contentRoleRelationMapper.insert(roleRelationDO);
            }
            // 游戏或者动漫, 处理CV
            if (contentType == ContentTypeEnum.ANIMATION || contentType == ContentTypeEnum.GAME) {
               updateCVInfo(contentId, role.getRoleId(), role.getCvs());
            }
        }
    }

    public void updateCVInfo (Long contentId, Long roleId, List<RoleManageQuery> cvs) {
        // 删除CV
        List<Long> cvsRelationId = cvs.stream().map(RoleManageQuery::getRelationId).filter(Objects::nonNull).collect(Collectors.toList());
        if (cvsRelationId.size() > 0) {
            LambdaQueryWrapper<RoleCvRelationDO> roleWrapper = Wrappers.<RoleCvRelationDO>lambdaQuery()
                    .eq(RoleCvRelationDO::getContentId, contentId)
                    .eq(RoleCvRelationDO::getRoleId, roleId)
                    .notIn(RoleCvRelationDO::getId, cvsRelationId);
            importMapperService.roleCvRelationMapper.delete(roleWrapper);
        }
        // 新增CV, 不存在才新增
        RoleCvRelationDO roleCvRelationDO = new RoleCvRelationDO();
        roleCvRelationDO.setContentId(contentId);
        roleCvRelationDO.setRoleId(roleId);
        for (RoleManageQuery cv : cvs) {
            if (cv.getRelationId() == null) {
                roleCvRelationDO.setCvId(cv.getRoleId());
                importMapperService.roleCvRelationMapper.insert(roleCvRelationDO);
            }
        }
    }

    public boolean isExistCV (Long contentId, Long roleId, Long cvId) {
        LambdaQueryWrapper<RoleCvRelationDO> wrapper = Wrappers.<RoleCvRelationDO>lambdaQuery()
                .eq(RoleCvRelationDO::getContentId, contentId)
                .eq(RoleCvRelationDO::getRoleId, roleId)
                .eq(RoleCvRelationDO::getCvId, cvId);
        int count = importMapperService.roleCvRelationMapper.selectCount(wrapper);
        return count > 0;
    }

    public void updateDiscInfo (Long contentId, List<ContentDiscQuery> discs) {
        // 删除歌曲
        List<Long> ids = Lists.newArrayList();
        for (ContentDiscQuery disc : discs) {
            for (ContentSongQuery song : disc.getMusicDiscList()) {
                Long id = song.getId();
                if (id != null) {
                    ids.add(id);
                }
            }
        }
        if (ids.size() > 0) {
            LambdaQueryWrapper<MusicDiscListDO> wrapper = Wrappers.<MusicDiscListDO>lambdaQuery()
                    .eq(MusicDiscListDO::getContentId, contentId)
                    .notIn(MusicDiscListDO::getId, ids);
            importMapperService.musicDiscListMapper.delete(wrapper);
        }
        // 新增歌曲
        for (ContentDiscQuery disc : discs) {
            Long discId = disc.getDisc();
            long discNum = getMaxDiscNum(contentId) + 1;
            for (ContentSongQuery songQuery : disc.getMusicDiscList()) {
                MusicDiscListDO discDO = BeanConvertUtils.BO2DO(songQuery, MusicDiscListDO.class);
                // 旧的元素歌曲不处理
                if (discDO.getId() == null) {
                    discDO.setContentId(contentId);
                    // 如果是旧的disc, 设置discId, 如果是新的disc, disc为最大序号+1
                    if (discId != null) {
                        discDO.setDisc(discId);
                    } else {
                        discDO.setDisc(discNum);
                    }
                    importMapperService.musicDiscListMapper.insert(discDO);
                }
            }
        }
    }

    /**
     * 更新人物的真实性
     * @param contentId
     * @param roleTruth
     */
    public void updateRoleTruth (Long contentId, RoleTruthEnum roleTruth) {
        LambdaUpdateWrapper<RoleTruthDO> wrapper = Wrappers.<RoleTruthDO>lambdaUpdate()
                .eq(RoleTruthDO::getRoleId, contentId)
                .set(RoleTruthDO::getRoleTruth, roleTruth);
        importMapperService.roleTruthMapper.update(new RoleTruthDO(), wrapper);
    }

    /**
     * 删除内容, 没测试
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long contentId) {
        ContentBasicInformationDO basicInfo = importMapperService.contentBasicInformationMapper.selectById(contentId);
        Preconditions.checkNotNull(basicInfo, "内容不存在");
        // 删除基本信息
        importMapperService.contentBasicInformationMapper.deleteById(contentId);
        // 删除额外信息
        LambdaQueryWrapper<ContentExtraInformationDO> extraInfoWrapper = Wrappers.<ContentExtraInformationDO>lambdaQuery()
                .eq(ContentExtraInformationDO::getContentId, contentId);
        importMapperService.contentExtraInformationMapper.delete(extraInfoWrapper);
        // 如果是音乐
        if (basicInfo.getType() == ContentTypeEnum.MUSIC) {
            // 删除disc
            LambdaQueryWrapper<MusicDiscListDO> discWrapper = Wrappers.<MusicDiscListDO>lambdaQuery()
                    .eq(MusicDiscListDO::getContentId, contentId);
            importMapperService.musicDiscListMapper.delete(discWrapper);
        }
        // 如果是人物
        else if (basicInfo.getType() == ContentTypeEnum.ROLE) {
            // 删除相关的forum讨论
            LambdaQueryWrapper<CommentForumDO> roleForumWrapper = Wrappers.<CommentForumDO>lambdaQuery()
                    .eq(CommentForumDO::getCommentTargetType, CommentTargetTypeEnum.ROLE)
                    .eq(CommentForumDO::getCommentTargetId, contentId);
            importMapperService.commentForumMapper.delete(roleForumWrapper);
            // 查看人物的真实性
            LambdaQueryWrapper<RoleTruthDO> roleTruthJudgeWrapper = Wrappers.<RoleTruthDO>lambdaQuery()
                    .eq(RoleTruthDO::getRoleId, contentId)
                    .last("limit 1");
            RoleTruthDO roleTruthDO = importMapperService.roleTruthMapper.selectOne(roleTruthJudgeWrapper);
            // 删除角色跟CV之间的关系
            LambdaQueryWrapper<RoleCvRelationDO> roleCVWrapper = Wrappers.<RoleCvRelationDO>lambdaQuery();
            if (roleTruthDO.getRoleTruth() == RoleTruthEnum.REAL) {
                // 真实人物，把跟角色的关系删掉
                roleCVWrapper.eq(RoleCvRelationDO::getCvId, contentId);
            } else if (roleTruthDO.getRoleTruth() == RoleTruthEnum.VIRTUAL) {
                // 虚拟人物，把他跟CV的关系删掉
                roleCVWrapper.eq(RoleCvRelationDO::getRoleId, contentId);
            }
            importMapperService.roleCvRelationMapper.delete(roleCVWrapper);
            // 删除人物的真实性
            importMapperService.roleTruthMapper.deleteById(roleTruthDO.getId());
        }
        // 删除相关的评分
        LambdaQueryWrapper<CommentScoreDO> commentScoreWrapper = Wrappers.<CommentScoreDO>lambdaQuery()
                .eq(CommentScoreDO::getContentId, contentId);
        importMapperService.commentScoreMapper.delete(commentScoreWrapper);
        // 删除相关的角色/制作人信息
        LambdaQueryWrapper<ContentRoleRelationDO> contentRoleWrapper = Wrappers.<ContentRoleRelationDO>lambdaQuery()
                .eq(ContentRoleRelationDO::getContentId, contentId);
        importMapperService.contentRoleRelationMapper.delete(contentRoleWrapper);
        // 删除相关的角色与cv之间的联系
        LambdaQueryWrapper<RoleCvRelationDO> roleCVWrapper = Wrappers.<RoleCvRelationDO>lambdaQuery()
                .eq(RoleCvRelationDO::getContentId, contentId);
        importMapperService.roleCvRelationMapper.delete(roleCVWrapper);
        // 删除相关的收藏
        LambdaQueryWrapper<FavoriteDO> favoriteWrapper = Wrappers.<FavoriteDO>lambdaQuery()
                .eq(FavoriteDO::getContentId, contentId);
        importMapperService.favoriteMapper.delete(favoriteWrapper);
        // 删除相关的日志
        LambdaQueryWrapper<JournalDO> journalWrapper = Wrappers.<JournalDO>lambdaQuery()
                .eq(JournalDO::getContentId, contentId);
        importMapperService.journalMapper.delete(journalWrapper);
    }


}
